import 'package:flutter/material.dart';
import 'dart:math';

class KLineChartPage extends StatefulWidget {
  const KLineChartPage({super.key});

  @override
  _KLineChartPageState createState() => _KLineChartPageState();
}

class _KLineChartPageState extends State<KLineChartPage> {
  List<KLineData> kLineData = generateRandomData(30);
  double offsetX = -5 * 15;
  double scale = 1.0;
  String timeFrame = "日";

  double crosshairX = -1; // 十字线 X 坐标
  double crosshairY = -1; // 十字线 Y 坐标
  KLineData? selectedData; // 当前选中的 K 线数据

  static List<KLineData> generateRandomData(int count) {
    Random random = Random();
    List<KLineData> data = [];
    double lastClose = 100.0;
    DateTime time = DateTime.now().subtract(Duration(days: count));

    for (int i = 0; i < count; i++) {
      double open = lastClose;
      double close =
          open + random.nextDouble() * 10 * (random.nextBool() ? 1 : -1);
      double high = max(open, close) + random.nextDouble() * 5;
      double low = min(open, close) - random.nextDouble() * 5;
      data.add(KLineData(
          time: time, open: open, close: close, high: high, low: low));
      lastClose = close;
      time = time.add(const Duration(days: 1));
    }

    return data;
  }

  void changeTimeFrame(String newFrame) {
    setState(() {
      timeFrame = newFrame;
      kLineData = generateRandomData(30);
      offsetX = 0.0;
    });
  }

  void loadMoreData() {
    DateTime latestTime = kLineData.first.time;
    List<KLineData> newData = fetchHistoryData(latestTime);

    setState(() {
      kLineData.insertAll(0, newData);
    });
  }

  List<KLineData> fetchHistoryData(DateTime earliestTime) {
    Random random = Random();
    List<KLineData> data = [];
    double lastClose = 100.0;

    DateTime time = earliestTime.subtract(const Duration(days: 0));
    for (int i = 1; i < 10; i++) {
      double open = lastClose;
      double close =
          open + random.nextDouble() * 10 * (random.nextBool() ? 1 : -1);
      double high = max(open, close) + random.nextDouble() * 5;
      double low = min(open, close) - random.nextDouble() * 5;
      data.insert(
          0,
          KLineData(
              time: time, open: open, close: close, high: high, low: low));
      lastClose = close;
      time = time.subtract(const Duration(days: 1));
    }

    return data;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("K 线图"),
        actions: [
          DropdownButton<String>(
            value: timeFrame,
            items: ["分", "时", "日", "月", "年"].map((String value) {
              return DropdownMenuItem<String>(
                value: value,
                child: Text(value),
              );
            }).toList(),
            onChanged: (value) {
              if (value != null) {
                changeTimeFrame(value);
              }
            },
          ),
        ],
      ),
      body: GestureDetector(
        onHorizontalDragUpdate: (details) {
          setState(() {
            offsetX += details.primaryDelta ?? 0;
          });

          if (offsetX > 50) {
            loadMoreData();
            offsetX = 0;
          }
        },
        onScaleUpdate: (details) {
          setState(() {
            scale = details.scale.clamp(0.5, 2.0);
          });
        },
        onLongPressStart: (details) {
          setState(() {
            crosshairX = _getSnappedCrosshairX(details.localPosition.dx);
            crosshairY = details.localPosition.dy;
            selectedData = _getSelectedKLineData(crosshairX);
          });
        },
        onLongPressMoveUpdate: (details) {
          setState(() {
            crosshairX = _getSnappedCrosshairX(details.localPosition.dx);
            crosshairY = details.localPosition.dy;
            selectedData = _getSelectedKLineData(crosshairX);
          });
        },
        onLongPressEnd: (_) {
          // setState(() {
          //   // 松开手指时隐藏十字线
          //   crosshairX = -1;
          //   crosshairY = -1;
          // });
        },
        onLongPressCancel: () {
          setState(() {
            // 取消长按时隐藏十字线
            crosshairX = -1;
            crosshairY = -1;
          });
        },
        child: Stack(
          children: [
            CustomPaint(
              size: const Size(double.infinity, 400),
              painter: KLinePainter(
                  kLineData, offsetX, scale, crosshairX, crosshairY),
            ),
            if (selectedData != null)
              Positioned(
                bottom: 20,
                left: 20,
                child: Container(
                  color: Colors.white,
                  padding: const EdgeInsets.all(8),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                          "时间: ${selectedData!.time.year}/${selectedData!.time.month}/${selectedData!.time.day}"),
                      Text("开盘价: ${selectedData!.open.toStringAsFixed(2)}"),
                      Text("收盘价: ${selectedData!.close.toStringAsFixed(2)}"),
                      Text("最高价: ${selectedData!.high.toStringAsFixed(2)}"),
                      Text("最低价: ${selectedData!.low.toStringAsFixed(2)}"),
                    ],
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }

  double _getSnappedCrosshairX(double touchX) {
    double closestX = double.infinity;
    double candleWidth = 10 * scale + 5 * scale; // 蜡烛的宽度加上间距
    double startX = offsetX;

    for (int i = 0; i < kLineData.length; i++) {
      double centerX = startX + (candleWidth / 2);
      if ((touchX - centerX).abs() < (touchX - closestX).abs()) {
        closestX = centerX;
      }
      startX += candleWidth;
    }
    return closestX - 2.5;
  }

  KLineData? _getSelectedKLineData(double crosshairX) {
    double candleWidth = 10 * scale;
    double space = 5 * scale;
    double startX = offsetX;
    for (int i = 0; i < kLineData.length; i++) {
      double centerX = startX + candleWidth / 2;
      if ((crosshairX - centerX).abs() <= candleWidth / 2) {
        return kLineData[i];
      }
      startX += candleWidth + space;
    }
    return null;
  }
}

class KLinePainter extends CustomPainter {
  final List<KLineData> data;
  final double offsetX;
  final double scale;
  final double crosshairX;
  final double crosshairY;

  KLinePainter(
      this.data, this.offsetX, this.scale, this.crosshairX, this.crosshairY);

/*
  @override
  void paint(Canvas canvas, Size size) {
    // 限制绘制区域为屏幕可见区域
    canvas.clipRect(Rect.fromLTWH(0, 0, size.width, size.height));
    Paint gridPaint = Paint()
      ..color = Colors.grey.withOpacity(0.5)
      ..strokeWidth = 0.5;

    double rowHeight = size.height / 5;
    double maxPrice = data.map((e) => e.high).reduce(max);
    double minPrice = data.map((e) => e.low).reduce(min);
    double priceStep = (maxPrice - minPrice) / 5;

    TextPainter textPainter = TextPainter(
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
    );

    for (int i = 0; i < 5; i++) {
      double priceLevel = size.height - (i * rowHeight);
      canvas.drawLine(
          Offset(0, priceLevel), Offset(size.width, priceLevel), gridPaint);

      textPainter.text = TextSpan(
        text: (minPrice + i * priceStep).toStringAsFixed(2),
        style: const TextStyle(color: Colors.black, fontSize: 10),
      );
      textPainter.layout();
      textPainter.paint(canvas, Offset(0, priceLevel - 10));
    }

    double candleWidth = 10 * scale;
    double space = 5 * scale;
    double startX = offsetX;

    Paint linePaint = Paint()
      ..color = Colors.black
      ..strokeWidth = 1.0;

    for (var item in data) {
      double highY = size.height -
          (item.high - minPrice) / (maxPrice - minPrice) * size.height;
      double lowY = size.height -
          (item.low - minPrice) / (maxPrice - minPrice) * size.height;
      double openY = size.height -
          (item.open - minPrice) / (maxPrice - minPrice) * size.height;
      double closeY = size.height -
          (item.close - minPrice) / (maxPrice - minPrice) * size.height;

      Paint candlePaint = Paint()
        ..color = item.close >= item.open ? Colors.green : Colors.red
        ..style = PaintingStyle.fill;

      linePaint = Paint()
        ..color = item.close >= item.open ? Colors.green : Colors.red
        ..strokeWidth = 1.0;

      canvas.drawLine(Offset(startX + candleWidth / 2, highY),
          Offset(startX + candleWidth / 2, lowY), linePaint);

      canvas.drawRect(
          Rect.fromLTRB(startX, openY, startX + candleWidth, closeY),
          candlePaint);

      startX += candleWidth + space;
    }

    if (crosshairX != -1 && crosshairY != -1) {
      Paint crosshairPaint = Paint()
        ..color = Colors.blue
        ..strokeWidth = 1.0;

      canvas.drawLine(Offset(crosshairX, 0), Offset(crosshairX, size.height),
          crosshairPaint);
      canvas.drawLine(Offset(0, crosshairY), Offset(size.width, crosshairY),
          crosshairPaint);
    }
  }
*/

  @override
  void paint(Canvas canvas, Size size) {
    // 获取当前屏幕可视范围的起始和结束索引
    double startX = offsetX;
    double endX = offsetX + size.width;

    // 计算每个蜡烛图的宽度
    double candleWidth = 10 * scale;
    double space = 5 * scale;

    // 计算数据可视范围的起始和结束位置
    int startIndex = ((startX) / (candleWidth + space)).floor();
    int endIndex = ((endX) / (candleWidth + space)).ceil();

    // 限制索引在数据范围内
    startIndex = startIndex.clamp(0, data.length - 1);
    endIndex = endIndex.clamp(0, data.length);

    // 在可视范围内计算最大值和最小值
    double maxPrice = double.minPositive;
    double minPrice = double.maxFinite;

    for (int i = startIndex; i < endIndex; i++) {
      var item = data[i];
      maxPrice = max(maxPrice, item.high);
      minPrice = min(minPrice, item.low);
    }

    // 绘制网格线和价格标签
    Paint gridPaint = Paint()
      ..color = Colors.grey.withOpacity(0.5)
      ..strokeWidth = 0.5;

    double rowHeight = size.height / 5;
    double priceStep = (maxPrice - minPrice) / 5;

    TextPainter textPainter = TextPainter(
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
    );

    // 绘制水平网格线和价格标签
    for (int i = 0; i < 5; i++) {
      double priceLevel = size.height - (i * rowHeight);
      canvas.drawLine(
          Offset(0, priceLevel), Offset(size.width, priceLevel), gridPaint);

      textPainter.text = TextSpan(
        text: (minPrice + i * priceStep).toStringAsFixed(2),
        style: const TextStyle(color: Colors.black, fontSize: 10),
      );
      textPainter.layout();
      textPainter.paint(canvas, Offset(0, priceLevel - 10));
    }

    // 绘制蜡烛图
    double currentX = startX; // 计算从哪里开始绘制

    Paint linePaint = Paint()
      ..color = Colors.black
      ..strokeWidth = 1.0;

    for (int i = startIndex; i < endIndex; i++) {
      var item = data[i];

      double highY = size.height -
          (item.high - minPrice) / (maxPrice - minPrice) * size.height;
      double lowY = size.height -
          (item.low - minPrice) / (maxPrice - minPrice) * size.height;
      double openY = size.height -
          (item.open - minPrice) / (maxPrice - minPrice) * size.height;
      double closeY = size.height -
          (item.close - minPrice) / (maxPrice - minPrice) * size.height;

      Paint candlePaint = Paint()
        ..color = item.close >= item.open ? Colors.green : Colors.red
        ..style = PaintingStyle.fill;

      // 绘制蜡烛图的上下影线
      canvas.drawLine(Offset(currentX + candleWidth / 2, highY),
          Offset(currentX + candleWidth / 2, lowY), linePaint);

      // 绘制蜡烛图的实体部分
      canvas.drawRect(
          Rect.fromLTRB(currentX, openY, currentX + candleWidth, closeY),
          candlePaint);

      // 更新 currentX 为下一个蜡烛图的起始位置
      currentX += candleWidth + space;
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true; // 这里可以根据实际情况进行优化，判断是否需要重绘
  }

//   @override
// bool shouldRepaint(covariant CustomPainter oldDelegate) {
//   return DateTime.now().millisecondsSinceEpoch - lastUpdateTime > 50;  // 限制每50ms更新一次
// }

  // @override
  // bool shouldRebuildSemantics(covariant CustomPainter oldDelegate) {
  //   return false; // 根据需要可以减少复杂度
  // }
}

class KLineData {
  final DateTime time;
  final double open;
  final double close;
  final double high;
  final double low;

  KLineData(
      {required this.time,
      required this.open,
      required this.close,
      required this.high,
      required this.low});
}
